源码LloydAsp/nfd: No Fraud / Node Forward Bot

特点

  • 基于 Workers 搭建,只要你的配额够,CF 不拉闸,那么就不存在跑路的问题。
  • 0 成本,连域名都不需要。
  • 接入反欺诈系统,当聊天对象有诈骗历史时,自动发出提醒。
  • 支持屏蔽用户,避免被骚扰。

搭建方法

首先去 @BotFather 创建一个新机器人,获取一个 API KEY(Token)。
然后使用 /setjoingroups 命令禁止机器人被添加到群组。
找一个获取 UUID 的网站,随机获取一个 UUID。
使用 @userinfobot 获取你的 TGID(或者 username_to_id_bot)。
然后前往 Cloudflare 控制台,创建一个示例 Workers。
然后在设置中添加环境变量。

  • ENV_BOT_TOKEN 变量,值为 Bot 的 Token
  • ENV_BOT_SECRET 变量,值为 UUID
  • ENV_ADMIN_UID 变量,值为 TGID

新建一个名字叫做 nfd 的 KV 数据库然后绑定 nfd = nfd。
回到上面,快速编辑里面编辑代码。

代码一

本文件 内容全部复制即可。
修改后保存并部署即可。
然后访问 https://demoworkers.dev/registerWebhook 注册 WebSoket 即可。
使用方法

  • 当其他用户给 bot 发消息,会被转发到 bot 创建者
  • 用户回复普通文字给转发的消息时,会回复到原消息发送者
  • 用户回复/block, /unblock, /checkblock 等命令会执行相关指令,不会回复到原消息发送者

代码二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
<span role="presentation">const TOKEN = ENV_BOT_TOKEN // Get it from @BotFather</span>
<span role="presentation">const WEBHOOK = '/endpoint'</span>
<span role="presentation">const SECRET = ENV_BOT_SECRET // A-Z, a-z, 0-9, _ and -</span>
<span role="presentation">const ADMIN_UID = ENV_ADMIN_UID // your user id, get it from https://t.me/username_to_id_bot</span>
<span role="presentation"></span>
<span role="presentation">const NOTIFY_INTERVAL = 3600 * 1000;</span>
<span role="presentation">const fraudDb = 'https://raw.githubusercontent.com/LloydAsp/nfd/main/data/fraud.db';</span>
<span role="presentation">const notificationUrl = 'https://raw.githubusercontent.com/LloydAsp/nfd/main/data/notification.txt'</span>
<span role="presentation">const startMsgUrl = 'https://raw.githubusercontent.com/LloydAsp/nfd/main/data/startMessage.md';</span>
<span role="presentation"></span>
<span role="presentation">const enable_notification = true</span>
<span role="presentation">/**</span>
<span role="presentation"> * Return url to telegram api, optionally with parameters added</span>
<span role="presentation"> */</span>
<span role="presentation">function apiUrl (methodName, params = null) {</span>
<span role="presentation"> let query = ''</span>
<span role="presentation"> if (params) {</span>
<span role="presentation"> query = '?' + new URLSearchParams(params).toString()</span>
<span role="presentation"> }</span>
<span role="presentation"> return `https://api.telegram.org/bot${TOKEN}/${methodName}${query}`</span>
<span role="presentation">}</span>
<span role="presentation"></span>
<span role="presentation">function requestTelegram(methodName, body, params = null){</span>
<span role="presentation"> return fetch(apiUrl(methodName, params), body)</span>
<span role="presentation"> .then(r => r.json())</span>
<span role="presentation">}</span>
<span role="presentation"></span>
<span role="presentation">function makeReqBody(body){</span>
<span role="presentation"> return {</span>
<span role="presentation"> method:'POST',</span>
<span role="presentation"> headers:{</span>
<span role="presentation"> 'content-type':'application/json'</span>
<span role="presentation"> },</span>
<span role="presentation"> body:JSON.stringify(body)</span>
<span role="presentation"> }</span>
<span role="presentation">}</span>
<span role="presentation"></span>
<span role="presentation">function sendMessage(msg = {}){</span>
<span role="presentation"> return requestTelegram('sendMessage', makeReqBody(msg))</span>
<span role="presentation">}</span>
<span role="presentation"></span>
<span role="presentation">function copyMessage(msg = {}){</span>
<span role="presentation"> return requestTelegram('copyMessage', makeReqBody(msg))</span>
<span role="presentation">}</span>
<span role="presentation"></span>
<span role="presentation">function forwardMessage(msg){</span>
<span role="presentation"> return requestTelegram('forwardMessage', makeReqBody(msg))</span>
<span role="presentation">}</span>
<span role="presentation"></span>
<span role="presentation">/**</span>
<span role="presentation"> * Wait for requests to the worker</span>
<span role="presentation"> */</span>
<span role="presentation">addEventListener('fetch', event => {</span>
<span role="presentation"> const url = new URL(event.request.url)</span>
<span role="presentation"> if (url.pathname === WEBHOOK) {</span>
<span role="presentation"> event.respondWith(handleWebhook(event))</span>
<span role="presentation"> } else if (url.pathname === '/registerWebhook') {</span>
<span role="presentation"> event.respondWith(registerWebhook(event, url, WEBHOOK, SECRET))</span>
<span role="presentation"> } else if (url.pathname === '/unRegisterWebhook') {</span>
<span role="presentation"> event.respondWith(unRegisterWebhook(event))</span>
<span role="presentation"> } else {</span>
<span role="presentation"> event.respondWith(new Response('No handler for this request'))</span>
<span role="presentation"> }</span>
<span role="presentation">})</span>
<span role="presentation"></span>
<span role="presentation">/**</span>
<span role="presentation"> * Handle requests to WEBHOOK</span>
<span role="presentation"> * https://core.telegram.org/bots/api#update</span>
<span role="presentation"> */</span>
<span role="presentation">async function handleWebhook (event) {</span>
<span role="presentation"> // Check secret</span>
<span role="presentation"> if (event.request.headers.get('X-Telegram-Bot-Api-Secret-Token') !== SECRET) {</span>
<span role="presentation"> return new Response('Unauthorized', { status: 403 })</span>
<span role="presentation"> }</span>
<span role="presentation"></span>
<span role="presentation"> // Read request body synchronously</span>
<span role="presentation"> const update = await event.request.json()</span>
<span role="presentation"> // Deal with response asynchronously</span>
<span role="presentation"> event.waitUntil(onUpdate(update))</span>
<span role="presentation"></span>
<span role="presentation"> return new Response('Ok')</span>
<span role="presentation">}</span>
<span role="presentation"></span>
<span role="presentation">/**</span>
<span role="presentation"> * Handle incoming Update</span>
<span role="presentation"> * https://core.telegram.org/bots/api#update</span>
<span role="presentation"> */</span>
<span role="presentation">async function onUpdate (update) {</span>
<span role="presentation"> if ('message' in update) {</span>
<span role="presentation"> await onMessage(update.message)</span>
<span role="presentation"> }</span>
<span role="presentation">}</span>
<span role="presentation"></span>
<span role="presentation">/**</span>
<span role="presentation"> * Handle incoming Message</span>
<span role="presentation"> * https://core.telegram.org/bots/api#message</span>
<span role="presentation"> */</span>
<span role="presentation">async function onMessage (message) {</span>
<span role="presentation"> if(message.text === '/start'){</span>
<span role="presentation"> let startMsg = await fetch(startMsgUrl).then(r => r.text())</span>
<span role="presentation"> return sendMessage({</span>
<span role="presentation"> chat_id:message.chat.id,</span>
<span role="presentation"> text:startMsg,</span>
<span role="presentation"> })</span>
<span role="presentation"> }</span>
<span role="presentation"> if(message.chat.id.toString() === ADMIN_UID){</span>
<span role="presentation"> if(!message?.reply_to_message?.chat){</span>
<span role="presentation"> return sendMessage({</span>
<span role="presentation"> chat_id:ADMIN_UID,</span>
<span role="presentation"> text:'使用方法,回复转发的消息,并发送回复消息,或者`/block`、`/unblock`、`/checkblock`等指令'</span>
<span role="presentation"> })</span>
<span role="presentation"> }</span>
<span role="presentation"> if(/^\/block$/.exec(message.text)){</span>
<span role="presentation"> return handleBlock(message)</span>
<span role="presentation"> }</span>
<span role="presentation"> if(/^\/unblock$/.exec(message.text)){</span>
<span role="presentation"> return handleUnBlock(message)</span>
<span role="presentation"> }</span>
<span role="presentation"> if(/^\/checkblock$/.exec(message.text)){</span>
<span role="presentation"> return checkBlock(message)</span>
<span role="presentation"> }</span>
<span role="presentation"> let guestChantId = await nfd.get('msg-map-' + message?.reply_to_message.message_id,</span>
<span role="presentation"> { type: "json" })</span>
<span role="presentation"> return copyMessage({</span>
<span role="presentation"> chat_id: guestChantId,</span>
<span role="presentation"> from_chat_id:message.chat.id,</span>
<span role="presentation"> message_id:message.message_id,</span>
<span role="presentation"> })</span>
<span role="presentation"> }</span>
<span role="presentation"> return handleGuestMessage(message)</span>
<span role="presentation">}</span>
<span role="presentation"></span>
<span role="presentation">async function handleGuestMessage(message){</span>
<span role="presentation"> let chatId = message.chat.id;</span>
<span role="presentation"> let isblocked = await nfd.get('isblocked-' + chatId, { type: "json" })</span>
<span role="presentation"> </span>
<span role="presentation"> if(isblocked){</span>
<span role="presentation"> return sendMessage({</span>
<span role="presentation"> chat_id: chatId,</span>
<span role="presentation"> text:'Your are blocked'</span>
<span role="presentation"> })</span>
<span role="presentation"> }</span>
<span role="presentation"></span>
<span role="presentation"> let forwardReq = await forwardMessage({</span>
<span role="presentation"> chat_id:ADMIN_UID,</span>
<span role="presentation"> from_chat_id:message.chat.id,</span>
<span role="presentation"> message_id:message.message_id</span>
<span role="presentation"> })</span>
<span role="presentation"> console.log(JSON.stringify(forwardReq))</span>
<span role="presentation"> if(forwardReq.ok){</span>
<span role="presentation"> await nfd.put('msg-map-' + forwardReq.result.message_id, chatId)</span>
<span role="presentation"> }</span>
<span role="presentation"> return handleNotify(message)</span>
<span role="presentation">}</span>
<span role="presentation"></span>
<span role="presentation">async function handleNotify(message){</span>
<span role="presentation"> // 先判断是否是诈骗人员,如果是,则直接提醒</span>
<span role="presentation"> // 如果不是,则根据时间间隔提醒:用户id,交易注意点等</span>
<span role="presentation"> let chatId = message.chat.id;</span>
<span role="presentation"> if(await isFraud(chatId)){</span>
<span role="presentation"> return sendMessage({</span>
<span role="presentation"> chat_id: ADMIN_UID,</span>
<span role="presentation"> text:`检测到骗子,UID${chatId}`</span>
<span role="presentation"> })</span>
<span role="presentation"> }</span>
<span role="presentation"> if(enable_notification){</span>
<span role="presentation"> let lastMsgTime = await nfd.get('lastmsg-' + chatId, { type: "json" })</span>
<span role="presentation"> if(!lastMsgTime || Date.now() - lastMsgTime > NOTIFY_INTERVAL){</span>
<span role="presentation"> await nfd.put('lastmsg-' + chatId, Date.now())</span>
<span role="presentation"> return sendMessage({</span>
<span role="presentation"> chat_id: ADMIN_UID,</span>
<span role="presentation"> text:await fetch(notificationUrl).then(r => r.text())</span>
<span role="presentation"> })</span>
<span role="presentation"> }</span>
<span role="presentation"> }</span>
<span role="presentation">}</span>
<span role="presentation"></span>
<span role="presentation">async function handleBlock(message){</span>
<span role="presentation"> let guestChantId = await nfd.get('msg-map-' + message.reply_to_message.message_id,</span>
<span role="presentation"> { type: "json" })</span>
<span role="presentation"> if(guestChantId === ADMIN_UID){</span>
<span role="presentation"> return sendMessage({</span>
<span role="presentation"> chat_id: ADMIN_UID,</span>
<span role="presentation"> text:'不能屏蔽自己'</span>
<span role="presentation"> })</span>
<span role="presentation"> }</span>
<span role="presentation"> await nfd.put('isblocked-' + guestChantId, true)</span>
<span role="presentation"></span>
<span role="presentation"> return sendMessage({</span>
<span role="presentation"> chat_id: ADMIN_UID,</span>
<span role="presentation"> text: `UID:${guestChantId}屏蔽成功`,</span>
<span role="presentation"> })</span>
<span role="presentation">}</span>
<span role="presentation"></span>
<span role="presentation">async function handleUnBlock(message){</span>
<span role="presentation"> let guestChantId = await nfd.get('msg-map-' + message.reply_to_message.message_id,</span>
<span role="presentation"> { type: "json" })</span>
<span role="presentation"></span>
<span role="presentation"> await nfd.put('isblocked-' + guestChantId, false)</span>
<span role="presentation"></span>
<span role="presentation"> return sendMessage({</span>
<span role="presentation"> chat_id: ADMIN_UID,</span>
<span role="presentation"> text:`UID:${guestChantId}解除屏蔽成功`,</span>
<span role="presentation"> })</span>
<span role="presentation">}</span>
<span role="presentation"></span>
<span role="presentation">async function checkBlock(message){</span>
<span role="presentation"> let guestChantId = await nfd.get('msg-map-' + message.reply_to_message.message_id,</span>
<span role="presentation"> { type: "json" })</span>
<span role="presentation"> let blocked = await nfd.get('isblocked-' + guestChantId, { type: "json" })</span>
<span role="presentation"></span>
<span role="presentation"> return sendMessage({</span>
<span role="presentation"> chat_id: ADMIN_UID,</span>
<span role="presentation"> text: `UID:${guestChantId}` + (blocked ? '被屏蔽' : '没有被屏蔽')</span>
<span role="presentation"> })</span>
<span role="presentation">}</span>
<span role="presentation"></span>
<span role="presentation">/**</span>
<span role="presentation"> * Send plain text message</span>
<span role="presentation"> * https://core.telegram.org/bots/api#sendmessage</span>
<span role="presentation"> */</span>
<span role="presentation">async function sendPlainText (chatId, text) {</span>
<span role="presentation"> return sendMessage({</span>
<span role="presentation"> chat_id: chatId,</span>
<span role="presentation"> text</span>
<span role="presentation"> })</span>
<span role="presentation">}</span>
<span role="presentation"></span>
<span role="presentation">/**</span>
<span role="presentation"> * Set webhook to this worker's url</span>
<span role="presentation"> * https://core.telegram.org/bots/api#setwebhook</span>
<span role="presentation"> */</span>
<span role="presentation">async function registerWebhook (event, requestUrl, suffix, secret) {</span>
<span role="presentation"> // https://core.telegram.org/bots/api#setwebhook</span>
<span role="presentation"> const webhookUrl = `${requestUrl.protocol}//${requestUrl.hostname}${suffix}`</span>
<span role="presentation"> const r = await (await fetch(apiUrl('setWebhook', { url: webhookUrl, secret_token: secret }))).json()</span>
<span role="presentation"> return new Response('ok' in r && r.ok ? 'Ok' : JSON.stringify(r, null, 2))</span>
<span role="presentation">}</span>
<span role="presentation"></span>
<span role="presentation">/**</span>
<span role="presentation"> * Remove webhook</span>
<span role="presentation"> * https://core.telegram.org/bots/api#setwebhook</span>
<span role="presentation"> */</span>
<span role="presentation">async function unRegisterWebhook (event) {</span>
<span role="presentation"> const r = await (await fetch(apiUrl('setWebhook', { url: '' }))).json()</span>
<span role="presentation"> return new Response('ok' in r && r.ok ? 'Ok' : JSON.stringify(r, null, 2))</span>
<span role="presentation">}</span>
<span role="presentation"></span>
<span role="presentation">async function isFraud(id){</span>
<span role="presentation"> id = id.toString()</span>
<span role="presentation"> let db = await fetch(fraudDb).then(r => r.text())</span>
<span role="presentation"> let arr = db.split('\n').filter(v => v)</span>
<span role="presentation"> console.log(JSON.stringify(arr))</span>
<span role="presentation"> let flag = arr.filter(v => v === id).length !== 0</span>
<span role="presentation"> console.log(flag)</span>
<span role="presentation"> return flag</span>
<span role="presentation">}</span>

修改后保存并部署即可。
然后访问 https://demo.demo.workers.dev/UUID 注册 WebSoket 即可。
私聊机器人,各项功能运行正常即可。